#include <iostream>
using std::cout;
using std::endl;

class Data{

public:
    Data(){
        cout << "Data()" << endl;
    }

    ~Data(){
        cout << "~Data()" << endl;
    }
    int getData(){
        return _data;
    }

private:
    int _data = 10;
};

class MiddleLayer{
public:
    MiddleLayer(Data * p)
    :_pdata(p)
    {
        cout << "MiddleLayer(Data *)" << endl; 
    }

    ~MiddleLayer(){
        cout << "~MiddleLayer()" << endl;
        if(_pdata){
            delete _pdata;
            _pdata = nullptr;
        }
    }
    Data * operator->(){
        return _pdata;
    }

    Data & operator*(){
        return *_pdata;
    }

private:
    Data * _pdata;
};

class ThirdLayer{
public:
    ThirdLayer(MiddleLayer * p)
    :_ml(p)
    {
        cout << "ThirdLayer(MiddleLayer*)" << endl;
    }
    ~ThirdLayer(){
        cout << "~ThirdLayer()" << endl;
        if(_ml){
            delete _ml;
            _ml = nullptr;
        }
    }
    //箭头访问运算符
    MiddleLayer & operator->(){
        return *_ml;
    }
    MiddleLayer & operator*(){
        return *_ml;
    }

private:
    MiddleLayer * _ml;
};


void test(){
    MiddleLayer ml(new Data());
    //ThirdLayer tl(&ml);
}
void test2(){
    //代码对应的内存图示应该什么样呢？
    ThirdLayer tl(new MiddleLayer(new Data()));
    //但是此时依然希望访问Data里面的成员函数
    //1.方案一：依然提供get函数暴露MiddleLayer*,解引用得到MiddleLayer
    //对象，再次调用MiddleLayer对象的get得到Data指针
    //2.方案二：重载箭头访问运算符和解引用运算符
    cout << tl->getData() << endl;
    //实际上上述代码，编译器是进行这样的处理
    //cout << tl->->getData()<< endl;
    cout << (tl.operator->()).operator->()->getData() << endl;
}

void test3(){
    ThirdLayer tl(new MiddleLayer(new Data()));
    cout << (*(*tl)).getData() << endl;
    //和下面的代码完全等价
    cout << tl.operator*().operator*().getData() <<endl;
}

void test4(){
    ThirdLayer tl(new MiddleLayer(new Data()));
    //目前的代码满足不了这个功能
    cout << (*tl).getData() << endl;
}
int main()
{
    test2();
    return 0;
}

